/*    file: UserAgent.h
 *    desc:
 *   
 * created: 2015-11-09
 *  author: chuanjiang.zh@qq.com
 * company: 
 */ 


#if !defined SIPAGENT_H_
#define SIPAGENT_H_

#include "Resip.h"
#include "AppConfig.h"

#include "resip/stack/EventStackThread.hxx"

#include "resip/dum/DumShutdownHandler.hxx"
#include "resip/dum/RegistrationHandler.hxx"
#include "resip/dum/InviteSessionHandler.hxx"
#include "resip/dum/ClientPagerMessage.hxx"
#include "resip/dum/ServerPagerMessage.hxx"
#include "resip/dum/PagerMessageHandler.hxx"
#include "resip/dum/OutOfDialogHandler.hxx"
#include "resip/dum/OutgoingEvent.hxx"


#include "MediaPort.h"
#include "CRegUserStore.h"
#include "RegUserAuthManager.h"

////////////////////////////////////////////////////////////////////////////
class UserAgent : public ThreadIf
                , public DumShutdownHandler
                , public ClientRegistrationHandler
                , public ServerRegistrationHandler
                , public InviteSessionHandler
                , public ClientPagerMessageHandler
                , public ServerPagerMessageHandler
                , public OutOfDialogHandler
{
public:
    UserAgent();
    virtual ~UserAgent();

    AppConfig& config();

    bool loadConfig(const char* filename);

    int startup();
    void shutdown();

    int getLocalPort();
    std::string getLocalUser();

    std::string getHostAddr();

    DialogUsageManager& getDum();

    NameAddr getLocalNameAddr();

    NameAddr getProxyAddr();

    std::string getContact();

    int getProxyPort();
    
    bool isProxyMode();

    std::string makeUri(const char* user);

    void test();


    void reg();

    void unreg();

    void call(const std::string& uri);

    void stopCall();

    bool reinvite();

    void sendMessage(const std::string& uri, const std::string& xml, const std::string& mime);
    void sendMessage(const std::string& uri, const std::string& xml);
    void sendDialogMessage(const std::string& xml, const std::string& mime);
    void sendDialogMessage(const std::string& xml);


    bool info(const std::string& xml, const std::string& mime);

    void options(const std::string& uri, const std::string& text, const std::string& mime);

    
    void setInviteWithSdp(bool withSdp);
    
    void setWindowMessage(HWND hwnd, UINT msg);

    void setOriginSdp(const char* sdp);

	void stopAudioCall();
	void setOriginAudioSdp(const char* sdp);

protected:
    bool m_inviteWithSdp;
    HWND    m_wnd;
    UINT    m_msg;

    SharedPtr< MediaPort >  m_mediaPort;
    std::string m_sdp;

    std::string m_playerPath;
    std::string m_rtpplayPath;
    std::string m_videoRtp;
    std::string m_audioRtp;

	CRegUserStore m_userStore;

	SharedPtr< MediaPort >	m_audioPort;
	InviteSessionHandle m_audioInviteSession;
	std::string	m_audioSdp;

protected:
    virtual void onSendMessage(const std::string& toUri, const std::string& xml,
                const std::string& mime);
    virtual void onRecvMessage(const std::string& fromUri, const std::string& xml,
                const std::string& mime);

    
    void findApp();

    MediaPort* createMediaPort();

protected:
    virtual void thread();

    virtual void onDumCanBeDeleted();

    // server registration
    /// Called when registration is refreshed
    virtual void onRefresh(ServerRegistrationHandle, const SipMessage& reg);
    /// called when one or more specified contacts is removed
    virtual void onRemove(ServerRegistrationHandle, const SipMessage& reg);
    /// Called when all the contacts are removed using "Contact: *"
    virtual void onRemoveAll(ServerRegistrationHandle, const SipMessage& reg);
    /** Called when one or more contacts are added. This is after
        authentication has all succeeded */
    virtual void onAdd(ServerRegistrationHandle handle, const SipMessage& reg);
    /// Called when a client queries for the list of current registrations
    virtual void onQuery(ServerRegistrationHandle, const SipMessage& reg);


    // Registration Handler ////////////////////////////////////////////////////////
    virtual void onSuccess(resip::ClientRegistrationHandle h, const resip::SipMessage& response);
    virtual void onFailure(resip::ClientRegistrationHandle h, const resip::SipMessage& response);
    virtual void onRemoved(resip::ClientRegistrationHandle h, const resip::SipMessage& response);
    virtual int onRequestRetry(resip::ClientRegistrationHandle h, int retryMinimum, const resip::SipMessage& msg);

    // invite handler
    /// called when an initial INVITE or the intial response to an outoing invite
    virtual void onNewSession(ClientInviteSessionHandle, InviteSession::OfferAnswerType oat, const SipMessage& msg);
    virtual void onNewSession(ServerInviteSessionHandle, InviteSession::OfferAnswerType oat, const SipMessage& msg);

    /// Received a failure response from UAS
    virtual void onFailure(ClientInviteSessionHandle, const SipMessage& msg);

    /// called when an in-dialog provisional response is received that contains a body
    virtual void onEarlyMedia(ClientInviteSessionHandle, const SipMessage&, const SdpContents&);
    virtual void onEarlyMedia(ClientInviteSessionHandle, const SipMessage&, const Contents&);

    /// called when dialog enters the Early state - typically after getting 18x
    virtual void onProvisional(ClientInviteSessionHandle, const SipMessage&);

    /// called when a dialog initiated as a UAC enters the connected state
    virtual void onConnected(ClientInviteSessionHandle, const SipMessage& msg);

    /// called when a dialog initiated as a UAS enters the connected state
    virtual void onConnected(InviteSessionHandle, const SipMessage& msg);

    virtual void onTerminated(InviteSessionHandle, InviteSessionHandler::TerminatedReason reason, const SipMessage* related);

    /// called when a fork that was created through a 1xx never receives a 2xx
    /// because another fork answered and this fork was canceled by a proxy.
    virtual void onForkDestroyed(ClientInviteSessionHandle);

    /// called when a 3xx with valid targets is encountered in an early dialog
    /// This is different then getting a 3xx in onTerminated, as another
    /// request will be attempted, so the DialogSet will not be destroyed.
    /// Basically an onTermintated that conveys more information.
    /// checking for 3xx respones in onTerminated will not work as there may
    /// be no valid targets.
    virtual void onRedirected(ClientInviteSessionHandle, const SipMessage& msg);

    /// called when an answer is received - has nothing to do with user
    /// answering the call
    virtual void onAnswer(InviteSessionHandle, const SipMessage& msg, const SdpContents&);
    /// called when an offer is received - must send an answer soon after this
    virtual void onOffer(InviteSessionHandle, const SipMessage& msg, const SdpContents&);
    /// called when an Invite w/out offer is sent, or any other context which
    /// requires an offer from the user
    virtual void onOfferRequired(InviteSessionHandle, const SipMessage& msg);

    /// called if an offer in a UPDATE or re-INVITE was rejected - not real
    /// useful. A SipMessage is provided if one is available
    virtual void onOfferRejected(InviteSessionHandle, const SipMessage* msg);

    /// called when INFO message is received
    /// the application must call acceptNIT() or rejectNIT()
    /// once it is ready for another message.
    virtual void onInfo(InviteSessionHandle, const SipMessage& msg);

    /// called when response to INFO message is received
    virtual void onInfoSuccess(InviteSessionHandle, const SipMessage& msg);
    virtual void onInfoFailure(InviteSessionHandle, const SipMessage& msg);

    /// called when MESSAGE message is received
    virtual void onMessage(InviteSessionHandle, const SipMessage& msg);

    /// called when response to MESSAGE message is received
    virtual void onMessageSuccess(InviteSessionHandle, const SipMessage& msg);
    virtual void onMessageFailure(InviteSessionHandle, const SipMessage& msg);

    /// called when an REFER message is received.  The refer is accepted or
    /// rejected using the server subscription. If the offer is accepted,
    /// DialogUsageManager::makeInviteSessionFromRefer can be used to create an
    /// InviteSession that will send notify messages using the ServerSubscription
    virtual void onRefer(InviteSessionHandle, ServerSubscriptionHandle, const SipMessage& msg);

    virtual void onReferNoSub(InviteSessionHandle, const SipMessage& msg);

    /// called when an REFER message receives a failure response
    virtual void onReferRejected(InviteSessionHandle, const SipMessage& msg);

    /// called when an REFER message receives an accepted response
    virtual void onReferAccepted(InviteSessionHandle, ClientSubscriptionHandle, const SipMessage& msg);


    // Called when a MESSAGE has been successfully sent
    virtual void onSuccess(ClientPagerMessageHandle, const SipMessage& status);
    //!kh!
    // Application could re-page the failed contents or just ingore it.
    virtual void onFailure(ClientPagerMessageHandle, const SipMessage& status, std::auto_ptr<Contents> contents);

    virtual void onMessageArrived(ServerPagerMessageHandle, const SipMessage& message);

    // Client Handlers
    virtual void onSuccess(ClientOutOfDialogReqHandle, const SipMessage& successResponse);
    virtual void onFailure(ClientOutOfDialogReqHandle, const SipMessage& errorResponse);
    // Server Handlers
    virtual void onReceivedRequest(ServerOutOfDialogReqHandle, const SipMessage& request);

protected:
    void setupMasterProfile();
    void setupDum();
    void teardown();

	void setupUser();

protected:
	static int m_iSeq;
    SipStack    m_stack;

    SharedPtr<FdPollGrp> m_pollGroup;
    SharedPtr<EventThreadInterruptor> m_interruptor;
    SharedPtr<EventStackThread> m_stackThread;

    SharedPtr<DialogUsageManager> m_dum;
    SharedPtr<MasterProfile> m_profile;

    SharedPtr<RegistrationPersistenceManager> m_regManager;
    SharedPtr<ServerAuthManager>    m_authManager;

    bool    m_shuttingDown;
    ClientRegistrationHandle m_regHandle;
    unsigned int m_regRetryDelayTime;

    InviteSessionHandle m_inviteSession;


};
////////////////////////////////////////////////////////////////////////////
#endif //SIPAGENT_H_

